hiho一下 第九十四周 数论三·约瑟夫问题

 数论三·约瑟夫问题

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi和小Ho的班级正在进行班长的选举,他们决定通过一种特殊的方式来选择班长。

首先N个候选人围成一个圈,依次编号为0..N-1。然后随机抽选一个数K,并0号候选人开始按从1到K的顺序依次报数,N-1号候选人报数之后,又再次从0开始。当有人报到K时,这个人被淘汰,从圈里出去。下一个人从1开始重新报数。

也就是说每报K个数字,都会淘汰一人。这样经过N-1轮报数之后,圈内就只剩下1个人了,这个人就作为新的班长。

举个例子,假如有5个候选人,K=3:

初始
0: 0 1 2 3 4
从0号开始报数,第1次是2号报到3
1: 0 1 - 3 4    	// 0 1 2, 2号候选人淘汰
从3号开始报数,第2次是0号报到3
2: - 1 3 4		// 3 4 0, 0号候选人淘汰
从1号开始报数,第3次是4号报到3
3: 1 3 -		// 1 3 4, 4号候选人淘汰
从1号开始报数,第4次是1号报到3
4: - 3			// 1 3 1, 1号候选人淘汰
  

对于N=5,K=3的情况,最后当选班长的人是编号为3的候选人。

小Ho:小Hi,我觉得当人数和K都确定的时候已经可以确定结果了。

小Hi:嗯,没错。

小Ho:我也想当班长,小Hi你能提前告诉我应该站在哪个位置么?

小Hi:我可以告诉你怎么去求最后一个被淘汰的位置,不过具体的值你得自己去求解。

小Ho:嗯,没问题,那么你快告诉我方法吧!

 

输入

第1行:1个正整数t,表示多组输入数据,1≤t≤100

第2..t+1行:每行2个正整数n,k,第i+1行表示第i组测试数据,2≤n≤1,000,000,000。2≤k≤1,000

输出

第1..t行:每行1个整数,第i行表示第i组数据的解

样例输入
2
5 3
8 3
样例输出
3
6
 

解答:

代码:
1,开始的时候用的循环链表法,提交之后一直TLE超时,仔细排查了下,因为当k特别大的时候,n比较小的时候,需要循环很多次链表,导致超时。
 1 #include<iostream>
 2 #include<list>
 3 #include<cstdlib>
 4 using namespace std;
 5  
 6 int solve(int total,int key){
 7 
 8     list<int>* table = new list<int>();
 9 
10     for (int i = 0; i < total; i++)
11     {
12         table->push_back(i);
13     }
14 
15     int shout = 1;
16     for (list<int>::iterator it = table->begin(); table->size() != 1;)
17     {
18         if (shout++ == key)
19         {
20             it = table->erase(it);
21             shout = 1;
22         }
23         else
24         {
25             ++it;
26         }
27 
28         if (it == table->end())
29         {
30             it = table->begin();
31         }
32     }
33     return *table->begin();
34 
35 }
36 int main(int argc, char* argv[])
37 {  
38     int n, total, key;    
39         cin>>n;  
40   
41     while (n--){
42         cin >> total >> key;
43 
44         cout << solve(total,key) << endl;
45     }
46      return 0; 
47  }

后来改的递推,效率提高了许多,AC了,这也体现了算法设计中,好的算法,不单单要解决实际问题,还要考虑效率问题,高效合理。

 1 #include<iostream>
 2 #include<list>
 3 #include<cstdlib>
 4 using namespace std;
 5 
 6 int solve(int total, int key)
 7 {
 8     if (total == 1)
 9         return 0;
10     if (total < key){
11         int anw = 0;
12         for (int i = 2; i <= total; i++)
13             anw = (anw + key) % i;
14         return anw;
15     }
16     
17     int anw = solve(total - total / key,key);
18     int temp = total % key;
19     if (anw < temp)
20         anw = anw - temp + total;
21     else
22         anw = anw - temp + (anw - temp) / (key - 1);
23     return anw;
24 }
25 
26 int main(int argc, char* argv[])
27 {
28     int n, total, key;
29     cin >> n;
30 
31     while (n--){
32         cin >> total >> key;
33         cout << solve(total, key) << endl;
34     }
35     return 0;
36 }

 

 最后在补充下左老师提供的代码,很简短!!!对左老师说“我不管,反正我一定要让你会”
 1 #include "iostream"
 2 
 3 using namespace std;
 4 
 5 int n, l;
 6 
 7 int getlive(int i, int m)//i长 m数
 8 {
 9     if (i == 1)
10         return 1;
11     return (getlive(i - 1, m) + m - 1) % i + 1;
12 }
13 
14 int main()
15 {
16     while (true)
17     {
18         cin >> n >> l;
19         cout<<getlive(n, l);
20     }
21 }

 

posted @ 2016-05-04 10:24  SeeKHit  阅读(362)  评论(0编辑  收藏  举报